var net = require('net');
var util = require('util');

var common = require('../common');
var ccResponse = require('../control/ResponseHooks');
var mResponse = require('./ResponseEntity');

/**
 * Store session handle information
 * 
 * @param id
 *            {string} Session identifier
 * @param game
 *            {string} Game identifier
 * 
 * @class Session
 * @author jmanero
 * @version 4/21/2012
 */
var Session = function(id) {
	var self = this;

	this.id = id;
	this.game = '';
	this.socket = new net.Socket();

	this.lastAccess = Date.now();

	this.request = {};
	this.response = {};

	this.clientBuffer = [];
	this.clientConnected = false;

	this.serverBuffer = [];
	this.serverConnected = false;

	this.destroyFlag = false;

	// Send buffer once connected
	this.socket.on('connect', function() {
		debug.log("	Connected to server");
		self.serverConnected = true;

		// Only one request per packet!
		while (self.serverBuffer.length > 0) {
			var xmlReq = self.serverBuffer.shift().toXML();
			debug.log("	Server <-- " + xmlReq + " <-- Buffer");

			this.write(xmlReq + "\n");
		}
	});

	// On data from server, send to client or buffer
	this.socket.on('data', function(data) {
		var xmlData = data.toString(); // Ensure that data isn't a buffer
		new ccResponse().handle(xmlData, self);
	});

	// Error Handler
	this.socket.on('error', function(e) {
		self.toClient(new mResponse().serverError(502,
				"Unable to connect to DLServer"));
		self.serverConnected = false;
	});

	// Handle server-side closure
	this.socket.on('end', function() {
		if (!self.destroyFlag) {
			self.toClient(new mResponse().serverError(502,
					"DLServer has closed connection"));

			self.releaseClient();
			self.destroyFlag = true;
		}
	});
};

/**
 * Send data and line break to DLServer
 * 
 * @param data
 */
Session.prototype.toServer = function(req) {
	if (this.serverConnected) {
		debug.log("	Server <-- " + req.toXML() + " <-- Client");
		this.socket.write(req.toXML() + "\n");
	} else {
		debug.log("	Buffer <-- " + JSON.stringify(req) + " <-- Client");
		this.serverBuffer.push(req);
	}
};

/**
 * Send response data to client
 * 
 * @param response
 */
Session.prototype.toClient = function(res) {
	if (this.clientConnected) {
		this.clientConnected = false;
		
		if (!Array.isArray(res)) {
			res = [ res ];
		}

		debug.log("	Server --> " + JSON.stringify(res) + " --> Client");

		this.response.send(res);
		this.releaseClient();
	} else {
		debug.log("	Server --> " + JSON.stringify(res) + " --> Buffer");
		this.clientBuffer.push(res);
	}
};

/**
 * Connect internal socket to DLServer
 */
Session.prototype.start = function(port, host) {
	if (!this.serverConnected) {
		try {
			var h = host || common.DLServer.host || "127.0.0.1";
			var p = port || common.DLServer.port;
			this.socket.connect(p, h);
		} catch (e) {
			this.serverConnected = false;
		}
	}
};

/**
 * Save temporary client connection
 * 
 * @param req
 * @param res
 */
Session.prototype.bindClient = function(req, res, next) {
	this.lastAccess = Date.now();
	var self = this;

	// Handle client-side closure
	req.on('close', function() {
		debug.log("	Browser closed connection: " + self.id);
		self.releaseClient();
	});

	req.on('end', function() {
		debug.log("	Browser sent FIN: " + self.id);
//		self.releaseClient();
	});
	// -------

	
	debug.log("	Client Bound: " + this.id);
	this.request = req;
	this.response = res;
	this.clientConnected = true;
	next();
};

/**
 * Clear temporary client connection information
 */
Session.prototype.releaseClient = function() {
	this.clientConnected = false;
	this.request = {};
	this.response = {};
	debug.log("	Client Released: " + this.id);
};

Session.prototype.destroy = function() {
	this.destroyFlag = true;
	this.socket.end();
	this.releaseClient();
};

module.exports = Session;
